package javaInterview;

import java.util.*;

/**
 * 小红书丝带AR特效问题
 * 
 * 题目描述：
 * 有一根虚拟丝带长度为 k，可以将其分割成若干段或保持一整段不动。
 * 每段长度只能取 a、b 或 c 中的一个，且不允许任何长度为 a 的段后面直接跟随长度为 c 的段。
 * 
 * 遍历所有长度 k (1≤k≤n)，统计合法的切割方案数。
 * 答案对 (10^9+7) 取模。
 * 
 * 输入格式：
 * - 第一行输入一个整数 T (1≤T≤10^4) 代表数据组数
 * - 每组测试数据：输入四个整数 n,a,b,c (1≤n,a,b,c≤10^6)
 *   代表最大丝带长度、可选分段长度 a,b,c。保证 a,b,c 两两互不相等
 * 
 * 输出格式：
 * - 对于每组测试数据，输出 n 个整数，表示长度为 1 到 n 的丝带的合法切割方案数
 */
public class RibbonAR {
    private static final int MOD = 1000000007;
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        
        for (int t = 0; t < T; t++) {
            int n = scanner.nextInt();
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int c = scanner.nextInt();
            
            long[] result = solve(n, a, b, c);
            
            // 输出结果
            for (int i = 0; i < n; i++) {
                if (i > 0) System.out.print(" ");
                System.out.print(result[i]);
            }
            System.out.println();
        }
        
        scanner.close();
    }
    
    /**
     * 解题思路：
     * 使用动态规划，定义状态：
     * dp[k][0] = 长度为k的丝带，最后一段是a的方案数
     * dp[k][1] = 长度为k的丝带，最后一段是b的方案数
     * dp[k][2] = 长度为k的丝带，最后一段是c的方案数
     * 
     * 状态转移：
     * - 如果最后一段是a：可以从任意状态转移（包括a、b、c）
     *   dp[k][0] = dp[k-a][0] + dp[k-a][1] + dp[k-a][2]
     * 
     * - 如果最后一段是b：可以从任意状态转移
     *   dp[k][1] = dp[k-b][0] + dp[k-b][1] + dp[k-b][2]
     * 
     * - 如果最后一段是c：不能从a转移（因为a后面不能直接跟c）
     *   dp[k][2] = dp[k-c][1] + dp[k-c][2]
     * 
     * 初始状态：
     * dp[a][0] = 1
     * dp[b][1] = 1
     * dp[c][2] = 1
     * 
     * 答案：dp[k][0] + dp[k][1] + dp[k][2]
     */
    public static long[] solve(int n, int a, int b, int c) {
        long[] result = new long[n];
        
        // dp[i][j] 表示长度为i，最后一段是第j种长度的方案数
        // j=0表示a, j=1表示b, j=2表示c
        long[][] dp = new long[n + 1][3];
        
        // 初始化
        if (a <= n) dp[a][0] = 1;
        if (b <= n) dp[b][1] = 1;
        if (c <= n) dp[c][2] = 1;
        
        // 动态规划
        for (int k = 1; k <= n; k++) {
            // 如果最后一段是a
            if (k >= a) {
                dp[k][0] = (dp[k][0] + dp[k - a][0]) % MOD;
                dp[k][0] = (dp[k][0] + dp[k - a][1]) % MOD;
                dp[k][0] = (dp[k][0] + dp[k - a][2]) % MOD;
            }
            
            // 如果最后一段是b
            if (k >= b) {
                dp[k][1] = (dp[k][1] + dp[k - b][0]) % MOD;
                dp[k][1] = (dp[k][1] + dp[k - b][1]) % MOD;
                dp[k][1] = (dp[k][1] + dp[k - b][2]) % MOD;
            }
            
            // 如果最后一段是c（不能从a转移）
            if (k >= c) {
                dp[k][2] = (dp[k][2] + dp[k - c][1]) % MOD;
                dp[k][2] = (dp[k][2] + dp[k - c][2]) % MOD;
            }
            
            // 统计当前长度的总方案数
            result[k - 1] = (dp[k][0] + dp[k][1] + dp[k][2]) % MOD;
        }
        
        return result;
    }
}

